iT邦幫忙

2021 iThome 鐵人賽

DAY 10
0
Mobile Development

IOS菜逼八連續30天挑戰系列 第 10

Day 10 Swift語法-進階篇(3/5)-Initialization

  • 分享至 

  • xImage
  •  

我們在定義類別或結構時,有時候會需要做初始化的動作,簡單說,就是給一個值,譬如我們在寫C的時候,如果我們要對一個值去做增加或減少的時候,我們會先給一個初始值,通常是0,譬如這樣:

int value = 0
for(int i  = 0; i<10; i++)
{
    value = value + i;
}

透過給初始值的方式,編譯器才知道,我們要累加的值是從0開始。

以此類推,如果我們這樣在class裡面宣告一個變數

這個時候編譯器就會報錯說你沒有初始化,接下來我們把它初始化:

class Example1 {
    
    var heigth = Int()
}

這邊的Int()就是給他一個值為0,當然我們也可以搭配自定義的初始化,例如這樣:

class Example2 {
    
    var height: Int
    
    init(height : Int) {
        self.height = height
    }
}

透過init(Initialization)這樣一來我們就可以自訂我們的初始化,但須留意的是,我們在這裡只宣告height是個Int型態,並沒有給他初始值,我們加入下面的程式碼

let tom = Example2(height: 180)
print(tom)

這樣一來我們就把180這個值給到height了

指定初始化跟便捷初始化(Designated and Convenience Initializer):

一般我們所使用的init都稱為Designated Initializer,但如果需要遇到補充的參數,而他也需要被初始化的時候,我們就可以使用Convenience Initializer了,譬如這樣:

lass Student{
    var height: Double
    var weight: Double
    var studentName: String
    
    init(height:Double, weight: Double, studentName: String){
        self.height = height
        self.weight = weight
        self.studentName = studentName
    }
    
    convenience init(newStudentName: String) {
        self.init(height: 175.0, weight: 60.0, studentName: newStudentName)
    }
    
}

然後我們宣告一個變數,然後把裡面的參數打印出來

透過這張圖,我們可以得到一個結果,因為我們已經在convenience init初始化我們的heigth跟weight了,但是我們沒有告訴編譯器studentName是什麼,我們只跟他說,我們用了一個newStudentName而他的值是String,所以,我們在最底下就必續給他一個值(學生姓名),給他值之後,他就會傳給convenience init,然後再給designated init,也就是,假設我們給peter,他就會是 peter -> newStudentName -> studentName,所以我們print是印出studentName~

var peter = Student(newStudentName: "peter")
print(peter.studentName)
//peter

雖然height跟weight,不能重新在下面給值,原因是因為已經被convenience init初始化過了,但是我們可以取用他的值,譬如這樣:

print(peter.height)
//175.0

這時候你會想說,可是我堅持要給height跟weight一個新的值,可不可以?答案是可以,但是我們就是透過一開始的designated init去給他值(上面圖片的第一行(height:weight:studentName:)),所以們連學生名字都要自己取一個新的,譬如:

var tom = Student(height: 154, weight: 162, studentName: "tom")
print(tom.height)
//154.0

當然,一個class我們通常只會使用一個,或兩個designated init,但是convenience init可以在一個class裡面同時多個使用(3個以上),譬如我們在弄一個convenience init並結合之前的 convenience init跟designated init來做個完整的練習:

import UIKit

class Student{
    var height: Double
    var weight: Double
    var studentName: String
    
    init(height:Double, weight: Double, studentName: String){
        self.height = height
        self.weight = weight
        self.studentName = studentName
    }
    
    convenience init(newStudentName: String) {
        self.init(height: 175.0, weight: 60.0, studentName: newStudentName)
    }
    
    convenience init(newStudentName2: String) {
        self.init(height: 162, weight: 50.0, studentName: newStudentName2)
    }
    
}

var peter = Student(newStudentName: "peter")
print(peter.studentName)
print("peter's height is \(peter.height) cm")

var tom = Student(height: 154, weight: 162, studentName: "tom")
print(" ")
print(tom.studentName)
print("toms's height is \(tom.height) cm")

var allen = Student(newStudentName2: "allen")
print(" ")
print(allen.studentName)
print("allen's weight is \(allen.weight) kg")

結果如下:

我們透過這個方式可以印證如swift官方文件所說的:
“Designated initializers must always delegate up
Convenience initializers must always delegate across“
這句話用他的圖片來看就是這樣:

這個情況是你有一個父類別,跟一個子類別,父類別裡有一個designated跟兩個convenience init,子類別有兩個designated init 跟一個convenience init,可以觀察下片頭的方向,他在講的就是:
convenience init是橫向(左右)傳值
designated則是縱向(上下)傳值

而當你有多個class則是長這樣

最後補充三個規則:
Rule 1
A designated initializer must call a designated initializer from its immediate superclass.
指定初始化只能從父類別叫另一個指定初始化器
Rule 2
A convenience initializer must call another initializer from the same class.
便捷初始化器調用另一個初始化器(有可能是指定初始化器也可能是另個便捷初始化器),必須是在同一個class
Rule 3
A convenience initializer must ultimately call a designated initializer.
便捷初始化器最終一定會呼叫一個指定初始化器(不管子類別還是父類別)


上一篇
Day 9 Swift語法-進階篇(2/5)-Inheritance
下一篇
Day 11 Swift語法-進階篇(4/5)-Protocol
系列文
IOS菜逼八連續30天挑戰30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言